#pragma once 
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<assert.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>
#include"log.hpp"

using namespace std;
class Socket
{
  private:
    int listen_sock;
    int port;
    static Socket* ptr;
    static pthread_mutex_t lock;
  public:
    static Socket* GetSocketObj(int port)
    {
      if(ptr==nullptr)
      {
        pthread_mutex_lock(&lock);
        if(ptr==nullptr)
        {
          ptr=new Socket(port);
        }
        pthread_mutex_unlock(&lock);
      }
      return ptr;
    }
  private:
    Socket(const int _port=8080):listen_sock(-1),port(_port)
    {}
    
    void Sock()
    {
      listen_sock=socket(AF_INET,SOCK_STREAM,0);
      assert(listen_sock>=0);
      LOG("INFO","SOCKET SUCCEED");
    }
    void Bind()
    {
      struct sockaddr_in address;
      address.sin_family=AF_INET;
      address.sin_port=htons(port);
      address.sin_addr.s_addr=INADDR_ANY;
      int ret=bind(listen_sock,(struct sockaddr*)&address,sizeof(address));
      assert(ret!=-1);
      LOG("INFO","BIND SUCCEED");
    }
    void Lisent()
    {
      int ret=listen(listen_sock,5);
      assert(ret!=-1);
      LOG("INFO","LISTEN SUCCEED");
    }
    
    ~Socket()
    {
      close(listen_sock);
    }
  public:
    void Init()
    {
      Sock();
      Bind();
      Lisent();
    }

    int GetLisent()
    {
      return listen_sock;
    }
};
Socket* Socket::ptr=nullptr;
pthread_mutex_t Socket::lock=PTHREAD_MUTEX_INITIALIZER;
